﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

public class EdgeDetection
{
    //Фильтр Робертса
    public static Bitmap RobertsFilter(Bitmap bitmap)
    {
        var img = new Bitmap(bitmap);
        int i, j, a, b, r;

        // карта яркости
        byte[,] brig = Histogram.CreateBrightMap(img);

        // Фильтрация
        for (i = 0; i < img.Height - 1; i++)
        {
            for (j = 0; j < img.Width - 1; j++)
            {
                a = brig[i, j] - brig[i + 1, j + 1];
                b = brig[i, j + 1] - brig[i + 1, j];

                r = (byte) (Math.Sqrt(a*a + b*b) + 0.5);
                if (r > 255) r = 255;

                img.SetPixel(j, i, Color.FromArgb(r, r, r));
            }
        }

        return img;
    }


    //Фильтр Собела
    public static Bitmap SobelFilter(Bitmap bitmap)
    {
        var img = new Bitmap(bitmap);

        int i, j, x, y, r;
        //карта яркости
        byte[,] b = Histogram.CreateBrightMap(img);

        // Фильтрация
        for (i = 1; i < img.Height - 1; i++)
        {
            for (j = 1; j < img.Width - 1; j++)
            {
                y = (b[i + 1, j - 1] + 2*b[i + 1, j] + b[i + 1, j + 1]) -
                    (b[i - 1, j - 1] + 2*b[i - 1, j] + b[i - 1, j + 1]);
                x = (b[i - 1, j - 1] + 2*b[i, j - 1] + b[i + 1, j - 1]) -
                    (b[i - 1, j + 1] + 2*b[i, j + 1] + b[i + 1, j + 1]);

                r = (int) (Math.Sqrt(x*x + y*y) + 0.5);
                if (r > 255) r = 255;

                img.SetPixel(j, i, Color.FromArgb(r, r, r));
            }
        }

        return img;
    }


    // Фильтр Кирша
    public static Bitmap KirshFilter(Bitmap bitmap)
    {
        var img = new Bitmap(bitmap);
        int i, j, s, t, r, max, sum;

        //карта яркости
        byte[,] b = Histogram.CreateBrightMap(img);

        // Фильтрация            
        for (i = 1; i < img.Height - 1; i++)
        {
            for (j = 1; j < img.Width - 1; j++)
            {
                sum = b[i - 1, j - 1] + b[i - 1, j] + b[i - 1, j + 1]; //p1
                s = sum;
                sum += b[i, j] + b[i, j + 1]; //p2
                sum += b[i + 1, j - 1] + b[i + 1, j] + b[i + 1, j + 1]; //p3	

                t = sum - s;
                max = Math.Abs(5*s - 3*t);
                s = s - b[i - 1, j - 1] + b[i, j];
                t = sum - s;
                r = Math.Abs(5*s - 3*t);
                if (r > max) max = r;
                s = s - b[i - 1, j] + b[i + 1, j + 1];
                t = sum - s;
                r = Math.Abs(5*s - 3*t);
                if (r > max) max = r;
                s = s - b[i - 1, j + 1] + b[i + 1, j];
                t = sum - s;
                r = Math.Abs(5*s - 3*t);
                if (r > max) max = r;
                s = s - b[i, j + 1] + b[i + 1, j - 1];
                t = sum - s;
                r = Math.Abs(5*s - 3*t);
                if (r > max) max = r;
                s = s - b[i + 1, j + 1] + b[i, j - 1];
                t = sum - s;
                r = Math.Abs(5*s - 3*t);
                if (r > max) max = r;
                s = s - b[i + 1, j] + b[i - 1, j - 1];
                t = sum - s;
                r = Math.Abs(5*s - 3*t);
                if (r > max) max = r;
                s = s - b[i, j - 1] + b[i - 1, j];
                t = sum - s;
                r = Math.Abs(5*s - 3*t);
                if (r > max) max = r;
                if (max > 255) max = 255;

                img.SetPixel(j, i, Color.FromArgb(max, max, max));
            }
        }
        return img;
    }

    // Фильтр Уоллеса
    public static Bitmap UollesFilter(Bitmap bitmap)
    {
        var img = new Bitmap(bitmap);

        int i, j, r;
        //карта яркости
        byte[,] b = Histogram.CreateBrightMap(img);

        // Фильтрация   
        for (i = 1; i < img.Height - 1; i++)
        {
            for (j = 1; j < img.Width - 1; j++)
            {
                r = (int) (0.25*Math.Log(Math.Pow(b[i, j], 4)/
                                         (b[i - 1, j]*b[i, j + 1]*b[i + 1, j]*b[i, j - 1]) + 0.5)*800);

                if (r > 255) r = 255;
                if (r < 0) r = 255;

                img.SetPixel(j, i, Color.FromArgb(r, r, r));
            }
        }

        return img;
    }

    //Статистический фильтр 
    public static Bitmap StatisticFilter(Bitmap bitmap, byte Aperture)
    {
        var img = new Bitmap(bitmap);

        int i, j, k, l, r;
        double sm, m, s;

        //карта яркости
        byte[,] b = Histogram.CreateBrightMap(img);

        // Фильтрация  
        for (i = Aperture/2; i < img.Height - Aperture/2; i++)
        {
            for (j = Aperture/2; j < img.Width - Aperture/2; j++)
            {
                m = 0;
                for (k = -1; k <= Aperture/2; k++)
                {
                    for (l = -1; l <= Aperture/2; l++)
                        m += b[i + k, l + j];
                }
                m /= (Aperture*Aperture);
                sm = 0;
                for (k = -1; k <= Aperture/2; k++)
                {
                    for (l = -1; l <= Aperture/2; l++)
                    {
                        s = b[k + i, l + j] - m;
                        sm += s*s;
                    }
                }
                sm = Math.Sqrt(sm)/Aperture;
                r = (int) ((b[i, j])*sm + 0.5);
                if (r > 255) r = 255;
                else if (r < 0) r = 0;
                img.SetPixel(j, i, Color.FromArgb(r, r, r));
            }
        }

        return img;
    }


    // Линейный фильтр
    public static Bitmap LinesFilter(Bitmap bitmap)
    {
        var img = new Bitmap(bitmap);
        
        int i, j, r;

        //карта яркости
        byte[,] b = Histogram.CreateBrightMap(img);

        // Фильтрация            
        for (i = 1; i < img.Height - 1; i++)
        {
            for (j = 1; j < img.Width - 1; j++)
            {
                r = -(b[i - 1, j - 1] + b[i - 1, j] + b[i - 1, j + 1] +
                      b[i, j - 1] + b[i, j + 1] +
                      b[i + 1, j - 1] + b[i + 1, j] + b[i + 1, j + 1]) +
                    (b[i, j] << 3);
                if (r > 255) r = 255;
                else if (r < 0) r = 0;
                img.SetPixel(j, i, Color.FromArgb(r, r, r));
            }
        }
        return img;
    }

    public static void HelpKirsh(Bitmap img)
    {
        for (var i = 1; i < img.Height - 1; i++)
        {
            for (var j = 1; j < img.Width - 1; j++)
            {
                var px = img.GetPixel(j, i);
                if (px.R + px.G + px.B < 255)
                    img.SetPixel(j, i, Color.Black);
            }
        }
    }

    //Фильтр Лапласа
    public static Bitmap LaplasFilter(Bitmap bitmap)
    {
        var img = new Bitmap(bitmap);

        int i, j, r;
        //карта яркости
        byte[,] b = Histogram.CreateBrightMap(img);

        // Фильтрация           
        for (i = 1; i < img.Height - 1; i++)
        {
            for (j = 1; j < img.Width - 1; j++)
            {
                r = -b[i - 1, j - 1] - 2*b[i - 1, j] - b[i - 1, j + 1] -
                    2*b[i, j - 1] + 12*b[i, j] - 2*b[i, j + 1] -
                    b[i + 1, j - 1] - 2*b[i + 1, j] - b[i + 1, j + 1];

                if (r > 255) r = 255;
                else if (r < 0) r = 0;
                img.SetPixel(j, i, Color.FromArgb(r, r, r));
            }
        }
        return img;
    }

    //Муравьиный фильтр 
    public static Bitmap AntColonyFilter(Bitmap bitmap)
    {
        var img = new Bitmap(bitmap);

        int i, j;
        int nPixel = 0, nPixelMax = 0;

        // Фильтрация               
        byte r, g, b;
        int idx = 0;

        //копируем байты изображения в массив
        BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadWrite,
                                          img.PixelFormat);
        var msv = new byte[bmpData.Stride*bmpData.Height];
        int stride = bmpData.Stride; // длина строки
        int nOffset = stride - img.Width*3; //смещение
        Marshal.Copy(bmpData.Scan0, msv, 0, msv.Length);
        img.UnlockBits(bmpData);

        idx = stride;
        for (i = 1; i < img.Height - 1; i++)
        {
            idx += 3;
            for (j = 1; j < img.Width - 1; j++)
            {
                //синий канал
                nPixelMax = Math.Abs(msv[idx - stride + 3] - msv[idx + stride - 3]);
                nPixel = Math.Abs(msv[idx + stride + 3] - msv[idx - stride - 3]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                nPixel = Math.Abs(msv[idx - stride] - msv[idx + stride]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                nPixel = Math.Abs(msv[idx + 3] - msv[idx - 3]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                if (nPixelMax < 0) nPixelMax = 0;
                b = (byte) nPixelMax;

                idx++;
                //зелёный канал
                nPixelMax = Math.Abs(msv[idx - stride + 3] - msv[idx + stride - 3]);
                nPixel = Math.Abs(msv[idx + stride + 3] - msv[idx - stride - 3]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                nPixel = Math.Abs(msv[idx - stride] - msv[idx + stride]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                nPixel = Math.Abs(msv[idx + 3] - msv[idx - 3]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                if (nPixelMax < 0) nPixelMax = 0;
                g = (byte) nPixelMax;

                idx++;
                //красный канал
                nPixelMax = Math.Abs(msv[idx - stride + 3] - msv[idx + stride - 3]);
                nPixel = Math.Abs(msv[idx + stride + 3] - msv[idx - stride - 3]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                nPixel = Math.Abs(msv[idx - stride] - msv[idx + stride]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                nPixel = Math.Abs(msv[idx + 3] - msv[idx - 3]);
                if (nPixel > nPixelMax) nPixelMax = nPixel;

                if (nPixelMax < 0) nPixelMax = 0;
                r = (byte) nPixelMax;

                img.SetPixel(j, i, Color.FromArgb(r, g, b));

                idx++;
            }
            idx += 3 + nOffset;
        }
        return img;
    }

    public static Bitmap CannyFilter(Bitmap img, float tH, float tL, int GSize, float Sigma)
    {
        var cnn = new Canny(img, tH, tL, GSize, Sigma);
        return (Bitmap) cnn.GetImage(cnn.EdgeMap);
    }
}